
package com.shop.cloud.weixin.admin.controller;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.weixin.admin.config.open.WxOpenConfiguration;
import com.shop.cloud.weixin.admin.mapper.WxFastRegistMapper;
import com.shop.cloud.weixin.admin.service.WxAppService;
import com.shop.cloud.weixin.admin.service.WxAuthAuditService;
import com.shop.cloud.weixin.common.constant.WxConstant;
import com.shop.cloud.weixin.common.constant.WxFastRegistStatus;
import com.shop.cloud.weixin.common.entity.WxApp;
import com.shop.cloud.weixin.common.entity.WxAuthAudit;
import com.shop.cloud.weixin.common.entity.WxFastRegist;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 开发平台回调控制
 * @author
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/open/notify")
@Tag(description = "opennotify", name = "开发平台回调控制")
public class WxOpenNotifyController {

	private final WxAppService wxAppService;
	private final WxFastRegistMapper wxFastRegistMapper;
	private final WxAuthAuditService wxAuthAuditService;

	/**
	 * 授权事件接收
	 * @param requestBody
	 * @param timestamp
	 * @param nonce
	 * @param signature
	 * @param encType
	 * @param msgSignature
	 * @return
	 */
	@RequestMapping("/receive_ticket")
    public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
								@RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
								@RequestParam(name = "encrypt_type", required = false) String encType,
								@RequestParam(name = "msg_signature", required = false) String msgSignature) {
        log.info(
                "\n接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encType, msgSignature, timestamp, nonce, requestBody);

        if (!StringUtils.equalsIgnoreCase("aes", encType)
                || !WxOpenConfiguration.getOpenService().getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        // aes加密的消息
        WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
				WxOpenConfiguration.getOpenService().getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
        log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
        try {
            WxOpenConfiguration.getOpenService().getWxOpenComponentService().route(inMessage);
			if("component_verify_ticket".equals(inMessage.getInfoType())){//推送 component_verify_ticket验证票据；https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/ThirdParty/token/component_verify_ticket.html
				log.info("推送component_verify_ticket验证票据:"+inMessage.getComponentVerifyTicket());
			}
			if("unauthorized".equals(inMessage.getInfoType())){//取消授权通知
				WxApp wxApp = wxAppService.findByAppId(inMessage.getAuthorizerAppid());
				if(wxApp != null){
					TenantContextHolder.setTenantId(wxApp.getTenantId());
					wxAppService.removeById(inMessage.getAuthorizerAppid());//删除账号
				}
			}
			if("notify_third_fasteregister".equals(inMessage.getInfoType())){//快速注册企业小程序注册审核事件推送
				WxFastRegist wxFastRegist = new WxFastRegist();
				wxFastRegist.setName(inMessage.getInfo().getName());
				wxFastRegist.setCode(inMessage.getInfo().getCode());
				wxFastRegist.setLegalPersonaWechat(inMessage.getInfo().getLegalPersonaWechat());
				wxFastRegist.setLegalPersonaName(inMessage.getInfo().getLegalPersonaName());
				wxFastRegist = wxFastRegistMapper.findByNameCodePersona(wxFastRegist);
				if(wxFastRegist != null){
					TenantContextHolder.setTenantId(wxFastRegist.getTenantId());//设置租户ID
					wxFastRegist.setStatus(String.valueOf(inMessage.getStatus()));
					wxFastRegist.setMsg(WxFastRegistStatus.valueOf("STATUS_" + Math.abs(inMessage.getStatus())).getMsg());
					//更新状态
					wxFastRegistMapper.updateById(wxFastRegist);
					if(WxFastRegistStatus.STATUS_0.getCode().equals(String.valueOf(inMessage.getStatus()))){//成功
						//添加小程序
						WxOpenQueryAuthResult queryAuthResult = WxOpenConfiguration.getOpenService().getWxOpenComponentService().getQueryAuth(inMessage.getAuthCode());
						String appId = queryAuthResult.getAuthorizationInfo().getAuthorizerAppid();
						WxOpenAuthorizerInfoResult wxOpenAuthorizerInfoResult = WxOpenConfiguration.getOpenService().getWxOpenComponentService().getAuthorizerInfo(appId);
						WxOpenAuthorizerInfo wxOpenAuthorizerInfo = wxOpenAuthorizerInfoResult.getAuthorizerInfo();
						WxApp wxApp = new WxApp();
						wxApp.setDelFlag(CommonConstants.STATUS_NORMAL);
						wxApp.setId(appId);
//						wxApp.setOrganId(wxFastRegist.getOrganId());
						wxApp.setShopId(wxFastRegist.getShopId());
						wxApp.setIsComponent(CommonConstants.YES);
						wxApp.setIsFastregist(WxConstant.WX_ISFASTREGIST_1);
						wxApp.setName(wxOpenAuthorizerInfo.getNickName());
						wxApp.setWeixinHao(wxOpenAuthorizerInfo.getAlias());
						wxApp.setWeixinSign(wxOpenAuthorizerInfo.getUserName());
						wxApp.setWeixinType(String.valueOf(wxOpenAuthorizerInfo.getServiceTypeInfo()));
						wxApp.setVerifyType(String.valueOf(wxOpenAuthorizerInfo.getVerifyTypeInfo()));
						wxApp.setLogo(wxOpenAuthorizerInfo.getHeadImg());
						wxApp.setQrCode(wxOpenAuthorizerInfo.getQrcodeUrl());
						wxApp.setPrincipalName(wxOpenAuthorizerInfo.getPrincipalName());
						wxApp.setSignature(wxOpenAuthorizerInfo.getSignature());
						wxApp.setAppType(WxConstant.WX_APP_TYPE_1);
						wxAppService.saveOrUpdate(wxApp);
					}
				}
			}else if("notify_3rd_wxa_auth".equals(inMessage.getInfoType())) {//小程序认证事件
				WxApp wxApp = wxAppService.findByAppId(inMessage.getSubAppId());
				if(wxApp != null){
					TenantContextHolder.setTenantId(wxApp.getTenantId());
				}
				//更新小程序认证信息
				wxAuthAuditService.update(new UpdateWrapper<WxAuthAudit>().lambda()
						.set(WxAuthAudit::getTaskStatus, String.valueOf(inMessage.getTaskStatus()))
						.set(WxAuthAudit::getApplyStatus, String.valueOf(inMessage.getApplyStatus()))
						.set(WxAuthAudit::getMessage, inMessage.getMessage())
						.set(WxAuthAudit::getDispatchInfo, JSONUtil.parseObj(inMessage.getDispatchInfo()))
						.eq(WxAuthAudit::getTaskId, inMessage.getTaskId()));
			}
			return "success";
        } catch (WxErrorException e) {
            log.error("receive_ticket", e);
			return "";
        }
    }

	/**
	 * 消息与事件接收
	 * @param requestBody
	 * @param appId
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @param openid
	 * @param encType
	 * @param msgSignature
	 * @return
	 */
    @RequestMapping("{appId}/callback")
    public Object callback(@RequestBody(required = false) String requestBody,
                           @PathVariable("appId") String appId,
                           @RequestParam("signature") String signature,
                           @RequestParam("timestamp") String timestamp,
                           @RequestParam("nonce") String nonce,
                           @RequestParam("openid") String openid,
                           @RequestParam("encrypt_type") String encType,
                           @RequestParam("msg_signature") String msgSignature) {
        log.info(
                "\n接收微信请求：[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
        if (!StringUtils.equalsIgnoreCase("aes", encType)
                || !WxOpenConfiguration.getOpenService().getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        String out = "";
        // aes加密的消息
        WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
				WxOpenConfiguration.getOpenService().getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
        log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
        // 全网发布测试用例
        if (StringUtils.equalsAnyIgnoreCase(appId, "wxd101a85aa106f53e", "wx570bc396a51b8ff8")) {
            try {
                if (StringUtils.equals(inMessage.getMsgType(), "text")) {
                    if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
                        out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
                                WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
                                        .fromUser(inMessage.getToUser())
                                        .toUser(inMessage.getFromUser())
                                        .build(),
								WxOpenConfiguration.getOpenService().getWxOpenConfigStorage()
                        );
                    } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
                        String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
                        WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
						WxOpenConfiguration.getOpenService().getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                    }
                } else if (StringUtils.equals(inMessage.getMsgType(), "event")) {
                    WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
					WxOpenConfiguration.getOpenService().getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                }
            } catch (WxErrorException e) {
                log.error("callback", e);
            }
        }else{
            WxMpXmlOutMessage outMessage = WxOpenConfiguration.getWxOpenMessageRouter().route(inMessage, appId);
            if(outMessage != null){
                out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, WxOpenConfiguration.getOpenService().getWxOpenConfigStorage());
            }
        }
        return out;
    }
}
